﻿#include <iostream>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavcodec/dxva2.h>
#include <libavutil/avutil.h>
}
#include "D3DRender.h"
#include "ffmpeg_dxva2.h"
AVPixelFormat GetHwFormat(AVCodecContext *s, const AVPixelFormat *pix_fmts)
{
	return AV_PIX_FMT_DXVA2_VLD;
}
void initdxva2()
{
	IDirect3DDeviceManager9* d3d_mgr_;

}
int main(int argc, char* argv[])
{
	avformat_network_init();
	

	int audio_idx = -1, video_idx = -1;
	AVCodec* video_codec = nullptr;
	AVCodecContext* video_codec_ctx = nullptr;
	AVCodec* audio_codec = nullptr;
	AVCodecContext* audio_codec_ctx = nullptr;
	AVBufferRef* hwdev_ctx = nullptr;
	AVPacket* packet = (AVPacket*)av_malloc(sizeof AVPacket);
	AVFrame* frame = av_frame_alloc();
	char hw_dev[] = "dxva2";

	AVFormatContext* format_ctx = avformat_alloc_context();

	if (avformat_open_input(&format_ctx, argv[1], nullptr, nullptr) != 0) {
		std::cout << "avformat_open_input" << std::endl;
		return -1;
	}
	if (avformat_find_stream_info(format_ctx, nullptr) < 0) {
		std::cout << "avformat_find_stream_info" << std::endl;
		return -1;
	}
	for (uint32_t i = 0;i < format_ctx->nb_streams;++i) {
		if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
			video_idx = i;
		}
		if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
			audio_idx = i;
		}
	}
	if (audio_idx == -1 && video_idx == -1) {
		std::cout << "no stream" << std::endl;
		return -1;
	}
	
	video_codec_ctx = avcodec_alloc_context3(nullptr);
	avcodec_parameters_to_context(video_codec_ctx, format_ctx->streams[video_idx]->codecpar);
	video_codec_ctx->pkt_timebase = format_ctx->streams[video_idx]->time_base;
	video_codec = avcodec_find_decoder(video_codec_ctx->codec_id);

#if 1//dxva2硬解
	video_codec_ctx->get_format = GetHwFormat;
	if (av_hwdevice_ctx_create(&hwdev_ctx, AV_HWDEVICE_TYPE_DXVA2, nullptr, nullptr, 0) < 0) {
		std::cout << "av_hwdevice_ctx_create" << std::endl;
		return -1;
	}
	video_codec_ctx->hw_device_ctx = av_buffer_ref(hwdev_ctx);
	video_codec_ctx->hwaccel_context;
#endif


	if (avcodec_open2(video_codec_ctx, video_codec, nullptr) != 0) {
		std::cout << "avcodec_open2" << std::endl;
		return -1;
	}
	D3DRender render((HWND)0x001F0742,video_codec_ctx->width,video_codec_ctx->height);
	while (av_read_frame(format_ctx,packet) == 0) {
		if (packet->stream_index != video_idx) {
			av_packet_unref(packet);
			continue;
		}
		int ret = avcodec_send_packet(video_codec_ctx, packet);
		av_packet_unref(packet);
		if (ret != 0) {
			switch (ret)
			{
			case AVERROR(EAGAIN):
				std::cout << "AVERROR(EAGAIN)" << std::endl;
				break;
			case AVERROR_EOF:
				std::cout << "AVERROR_EOF" << std::endl;
				break;
			case AVERROR(EINVAL):
				std::cout << "AVERROR(EINVAL)" << std::endl;
				break;
			case AVERROR(ENOMEM):
				std::cout << "AVERROR(ENOMEM)" << std::endl;
				break;
			default:
				break;
			}
			char err[256] = { 0 };
			av_strerror(ret, err, 256);
			std::cout << err << std::endl;
			continue;
		}
		
		while (avcodec_receive_frame(video_codec_ctx, frame) == 0) {
			render.render((LPDIRECT3DSURFACE9)frame->data[3]);
			Sleep(10);
			//av_frame_unref(frame);
		}
	}
}


